#include "HTU31.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <math.h>
#include <inttypes.h>

static const char *TAG = "HTU31";

// HTU31 CRC-8多项式: 0x131 (CRC-8-CCITT)
#define HTU31_CRC8_POLYNOMIAL 0x31
#define HTU31_CRC8_INIT 0xFF

/**
 * @brief 计算HTU31专用CRC-8校验值 (参考Adafruit库)
 * 
 * @param value 16位数据值
 * @return uint8_t CRC-8校验值
 */
uint8_t htu31_crc8(uint16_t value)
{
    uint32_t polynom = 0x988000; // x^8 + x^5 + x^4 + 1
    uint32_t msb = 0x800000;
    uint32_t mask = 0xFF8000;
    uint32_t result = (uint32_t)value << 8; // Pad with zeros as specified in spec

    while (msb != 0x80) {
        // Check if msb of current value is 1 and apply XOR mask
        if (result & msb)
            result = ((result ^ polynom) & mask) | (result & ~mask);

        // Shift by one
        msb >>= 1;
        mask >>= 1;
        polynom >>= 1;
    }
    return (uint8_t)result;
}

/**
 * @brief 校验CRC-8
 * 
 * @param value 16位数据值
 * @param expected_crc 期望的CRC值
 * @return true CRC校验通过
 * @return false CRC校验失败
 */
bool htu31_check_crc(uint16_t value, uint8_t expected_crc)
{
    return htu31_crc8(value) == expected_crc;
}

/**
 * @brief 写命令到HTU31
 * 
 * @param handle HTU31句柄
 * @param cmd 命令字节
 * @return esp_err_t 
 */
static esp_err_t htu31_write_cmd(htu31_handle_t *handle, uint8_t cmd)
{
    i2c_cmd_handle_t cmd_handle = i2c_cmd_link_create();
    
    i2c_master_start(cmd_handle);
    i2c_master_write_byte(cmd_handle, (handle->device_addr << 1) | I2C_MASTER_WRITE, true);
    i2c_master_write_byte(cmd_handle, cmd, true);
    i2c_master_stop(cmd_handle);
    
    esp_err_t ret = i2c_master_cmd_begin(handle->i2c_port, cmd_handle, pdMS_TO_TICKS(1000));
    i2c_cmd_link_delete(cmd_handle);
    
    return ret;
}

/**
 * @brief 从HTU31读取数据
 * 
 * @param handle HTU31句柄
 * @param data 数据缓冲区
 * @param len 读取长度
 * @return esp_err_t 
 */
static esp_err_t htu31_read_data(htu31_handle_t *handle, uint8_t *data, size_t len)
{
    i2c_cmd_handle_t cmd_handle = i2c_cmd_link_create();
    
    i2c_master_start(cmd_handle);
    i2c_master_write_byte(cmd_handle, (handle->device_addr << 1) | I2C_MASTER_READ, true);
    
    if (len > 1) {
        i2c_master_read(cmd_handle, data, len - 1, I2C_MASTER_ACK);
    }
    i2c_master_read_byte(cmd_handle, data + len - 1, I2C_MASTER_NACK);
    
    i2c_master_stop(cmd_handle);
    
    esp_err_t ret = i2c_master_cmd_begin(handle->i2c_port, cmd_handle, pdMS_TO_TICKS(1000));
    i2c_cmd_link_delete(cmd_handle);
    
    return ret;
}

/**
 * @brief 初始化HTU31传感器
 * 
 * @param handle HTU31句柄
 * @param i2c_port I2C端口号
 * @param device_addr 设备I2C地址
 * @return esp_err_t 
 */
esp_err_t htu31_init(htu31_handle_t *handle, i2c_port_t i2c_port, uint8_t device_addr)
{
    if (handle == NULL) {
        return ESP_ERR_INVALID_ARG;
    }
    
    handle->i2c_port = i2c_port;
    handle->device_addr = device_addr;
    handle->initialized = false;
    handle->temperature_offset = 0.0;  // 初始化温度校准偏移量
    handle->humidity_offset = 0.0;     // 初始化湿度校准偏移量
    
    // 检查设备是否存在
    if (!htu31_is_connected(handle)) {
        ESP_LOGE(TAG, "HTU31 设备未连接，地址: 0x%02X", device_addr);
        return ESP_ERR_NOT_FOUND;
    }
    
    // 执行软复位
    esp_err_t ret = htu31_soft_reset(handle);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "HTU31 软复位失败");
        return ret;
    }
    
    handle->initialized = true;
    ESP_LOGI(TAG, "HTU31 初始化成功，地址: 0x%02X", device_addr);
    
    return ESP_OK;
}

/**
 * @brief 软复位HTU31
 * 
 * @param handle HTU31句柄
 * @return esp_err_t 
 */
esp_err_t htu31_soft_reset(htu31_handle_t *handle)
{
    if (handle == NULL) {
        return ESP_ERR_INVALID_ARG;
    }
    
    esp_err_t ret = htu31_write_cmd(handle, HTU31_CMD_SOFT_RESET);
    if (ret == ESP_OK) {
        vTaskDelay(pdMS_TO_TICKS(20)); // 等待复位完成
        ESP_LOGI(TAG, "HTU31 软复位完成");
    }
    
    return ret;
}

/**
 * @brief 检查HTU31是否连接
 * 
 * @param handle HTU31句柄
 * @return true 设备已连接
 * @return false 设备未连接
 */
bool htu31_is_connected(htu31_handle_t *handle)
{
    if (handle == NULL) {
        return false;
    }
    
    i2c_cmd_handle_t cmd_handle = i2c_cmd_link_create();
    i2c_master_start(cmd_handle);
    i2c_master_write_byte(cmd_handle, (handle->device_addr << 1) | I2C_MASTER_WRITE, true);
    i2c_master_stop(cmd_handle);
    
    esp_err_t ret = i2c_master_cmd_begin(handle->i2c_port, cmd_handle, pdMS_TO_TICKS(1000));
    i2c_cmd_link_delete(cmd_handle);
    
    return ret == ESP_OK;
}

/**
 * @brief 读取温湿度数据
 * 
 * @param handle HTU31句柄
 * @param data 温湿度数据结构指针
 * @return esp_err_t 
 */
esp_err_t htu31_read_temperature_humidity(htu31_handle_t *handle, htu31_data_t *data)
{
    if (handle == NULL || data == NULL || !handle->initialized) {
        return ESP_ERR_INVALID_ARG;
    }
    
    uint8_t cmd_data[6];
    
    // 步骤1: 发送转换命令 (参考Adafruit库)
    esp_err_t ret = htu31_write_cmd(handle, HTU31_CMD_CONVERSION);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "发送转换命令失败");
        return ret;
    }
    
    // 等待转换完成
    vTaskDelay(pdMS_TO_TICKS(HTU31_CONVERSION_DELAY));
    
    // 步骤2: 发送读取命令并读取数据
    ret = htu31_write_cmd(handle, HTU31_CMD_READ_TEMP_HUM);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "发送读取命令失败");
        return ret;
    }
    
    // 读取6字节数据
    ret = htu31_read_data(handle, cmd_data, 6);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "读取传感器数据失败");
        return ret;
    }
    
    // 添加调试输出
    // ESP_LOGI(TAG, "读取原始数据: %02X %02X %02X %02X %02X %02X", 
            //  cmd_data[0], cmd_data[1], cmd_data[2], cmd_data[3], cmd_data[4], cmd_data[5]);
    
    // 计算温度原始值
    uint16_t temp_raw = (cmd_data[0] << 8) | cmd_data[1];
    uint8_t temp_crc = htu31_crc8(temp_raw);
    
    // 计算湿度原始值
    uint16_t humid_raw = (cmd_data[3] << 8) | cmd_data[4];
    uint8_t humid_crc = htu31_crc8(humid_raw);
    
    // ESP_LOGI(TAG, "CRC校验: 温度=%02X(期望%02X), 湿度=%02X(期望%02X)", 
            //  temp_crc, cmd_data[2], humid_crc, cmd_data[5]);
    
    // 校验CRC
    if (!htu31_check_crc(temp_raw, cmd_data[2])) {
        ESP_LOGE(TAG, "温度数据CRC校验失败");
        return ESP_ERR_INVALID_CRC;
    }
    
    if (!htu31_check_crc(humid_raw, cmd_data[5])) {
        ESP_LOGE(TAG, "湿度数据CRC校验失败");
        return ESP_ERR_INVALID_CRC;
    }
    
    // 转换温度 (°C) - HTU31公式: T = (raw / 65535) * 165 - 40
    data->temperature = (float)temp_raw / 65535.0 * 165.0 - 40.0;
    
    // 应用温度校准：实际温度 = 传感器温度 - 校准偏移量
    data->temperature -= handle->temperature_offset;
    
    // 转换湿度 (%RH) - HTU31公式: RH = (raw / 65535) * 100
    data->humidity = (float)humid_raw / 65535.0 * 100.0;
    
    // 应用湿度校准：实际湿度 = 传感器湿度 - 校准偏移量
    data->humidity -= handle->humidity_offset;
    
    // ESP_LOGI(TAG, "转换后数据: 温度=%.2f°C(已校准), 湿度=%.2f%%RH(已校准)", data->temperature, data->humidity);
    
    return ESP_OK;
}

/**
 * @brief 读取温度
 * 
 * @param handle HTU31句柄
 * @param temperature 温度指针
 * @return esp_err_t 
 */
esp_err_t htu31_read_temperature(htu31_handle_t *handle, float *temperature)
{
    htu31_data_t data;
    esp_err_t ret = htu31_read_temperature_humidity(handle, &data);
    if (ret == ESP_OK) {
        *temperature = data.temperature;
    }
    return ret;
}

/**
 * @brief 读取湿度
 * 
 * @param handle HTU31句柄
 * @param humidity 湿度指针
 * @return esp_err_t 
 */
esp_err_t htu31_read_humidity(htu31_handle_t *handle, float *humidity)
{
    htu31_data_t data;
    esp_err_t ret = htu31_read_temperature_humidity(handle, &data);
    if (ret == ESP_OK) {
        *humidity = data.humidity;
    }
    return ret;
}

/**
 * @brief 控制加热器
 * 
 * @param handle HTU31句柄
 * @param enable true-开启加热器，false-关闭加热器
 * @return esp_err_t 
 */
esp_err_t htu31_heater_enable(htu31_handle_t *handle, bool enable)
{
    if (handle == NULL || !handle->initialized) {
        return ESP_ERR_INVALID_ARG;
    }
    
    uint8_t cmd = enable ? HTU31_CMD_HEATER_ON : HTU31_CMD_HEATER_OFF;
    esp_err_t ret = htu31_write_cmd(handle, cmd);
    
    if (ret == ESP_OK) {
        ESP_LOGI(TAG, "加热器%s", enable ? "开启" : "关闭");
    }
    
    return ret;
}

/**
 * @brief 读取序列号
 * 
 * @param handle HTU31句柄
 * @param serial_number 序列号指针
 * @return esp_err_t 
 */
esp_err_t htu31_read_serial_number(htu31_handle_t *handle, uint32_t *serial_number)
{
    if (handle == NULL || serial_number == NULL || !handle->initialized) {
        return ESP_ERR_INVALID_ARG;
    }
    
    uint8_t reply[4];
    
    // 发送读取序列号命令 (参考Adafruit库)
    esp_err_t ret = htu31_write_cmd(handle, HTU31_CMD_READ_SERIAL);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "发送读取序列号命令失败");
        return ret;
    }
    
    // 读取4字节序列号数据
    ret = htu31_read_data(handle, reply, 4);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "读取序列号数据失败");
        return ret;
    }
    
    ESP_LOGI(TAG, "序列号原始数据: %02X %02X %02X %02X", 
             reply[0], reply[1], reply[2], reply[3]);
    
    // 组合序列号 (32位)
    *serial_number = ((uint32_t)reply[0] << 24) | ((uint32_t)reply[1] << 16) |
                     ((uint32_t)reply[2] << 8) | reply[3];
    
    ESP_LOGI(TAG, "序列号: 0x%08" PRIX32, *serial_number);
    
    return ESP_OK;
}

/**
 * @brief 设置温度校准偏移量（手动设置）
 * 
 * @param handle HTU31句柄
 * @param offset 温度偏移量（°C）- 实际温度 = 传感器温度 - offset
 * @return esp_err_t 
 */
esp_err_t htu31_set_temperature_offset(htu31_handle_t *handle, float offset)
{
    if (handle == NULL || !handle->initialized) {
        return ESP_ERR_INVALID_ARG;
    }
    
    handle->temperature_offset = offset;
    ESP_LOGI(TAG, "温度校准偏移量设置为: %.2f°C", offset);
    
    return ESP_OK;
}

/**
 * @brief 设置湿度校准偏移量（手动设置）
 * 
 * @param handle HTU31句柄
 * @param offset 湿度偏移量（%RH）- 实际湿度 = 传感器湿度 - offset
 * @return esp_err_t 
 */
esp_err_t htu31_set_humidity_offset(htu31_handle_t *handle, float offset)
{
    if (handle == NULL || !handle->initialized) {
        return ESP_ERR_INVALID_ARG;
    }
    
    handle->humidity_offset = offset;
    ESP_LOGI(TAG, "湿度校准偏移量设置为: %.2f%%RH", offset);
    
    return ESP_OK;
}

/**
 * @brief 获取当前温度偏移量
 * 
 * @param handle HTU31句柄
 * @return float 当前的温度偏移量
 */
float htu31_get_temperature_offset(htu31_handle_t *handle)
{
    if (handle == NULL) {
        return 0.0;
    }
    
    return handle->temperature_offset;
}

/**
 * @brief 获取当前湿度偏移量
 * 
 * @param handle HTU31句柄
 * @return float 当前的湿度偏移量
 */
float htu31_get_humidity_offset(htu31_handle_t *handle)
{
    if (handle == NULL) {
        return 0.0;
    }
    
    return handle->humidity_offset;
} 